//
// Created by yunnan xu on 2020/12/6.
//

#include "MeshHelper.h"
#include "ResourceMgr.h"
#include "EngineCore.h"
#include "ext.hpp"
#include <unordered_map>
#include <vector>

MeshHelper::MeshHelper()
{
    objFileParser = std::make_shared<ObjFileParser>();
}

void MeshHelper::GetMeshData(const char * file_path, std::unordered_map<VertexAttribType, uint8_t*> & vertex_data, uint8_t * index_data)
{
    if (strstr(file_path, ".obj") == NULL)
    {
        LOGE("GetMeshData invalid file_path = %s", file_path);
        return;
    }

    long file_size = ResourceMgr::GetInstance()->GetFileLength(file_path, AASSET_MODE_BUFFER);
    unsigned char * modelFileContent = new unsigned char [file_size];

    int read_res = ResourceMgr::GetInstance()->ReadFile(file_path, modelFileContent, file_size, AASSET_MODE_BUFFER);
    if (read_res < 0)
    {
        LOGE("AssimpModel ReadFile error filepath = %s, res = %d", file_path, read_res);
        return;
    }
    else {
        LOGI("AssimpModel filepath = %s, read_res = %d", file_path, read_res);
    }

    objFileParser->FillMeshData(modelFileContent, file_size, vertex_data, index_data);
}


/*
 *  OBJ 文件格式：https://en.wikipedia.org/wiki/Wavefront_.obj_file
 * */
void ObjFileParser::FillMeshData(const unsigned char * model_data, int data_length, std::unordered_map<VertexAttribType, uint8_t*> & vertex_data, uint8_t * index_data)
{
    int index = 0;
    int line_start = 0;
    int line_end = 0;

    std::vector<float> position_list;
    std::vector<float> texture_list;
    std::vector<float> normal_list;

    bool has_init_vertex_data = false;

    while (index < data_length)
    {
        line_start = index;

        while (index < data_length && model_data[index] != '\n')
        {
            index ++;
        }

        line_end = index;

        if (model_data[line_start] == '#')
        {
            continue;
        }
        // position
        else if (model_data[line_start] == 'v' && model_data[line_start + 1] == ' ')
        {
            char buffer[3][64] = {};
            int float_count = 0;
            int j = 0;
            for (int i = line_start + 2; i < line_end; i++)
            {
                 if (model_data[i] != ' ' && model_data[i] != '\n')
                 {
                     buffer[float_count][j++] = model_data[i];
                 } else
                 {
                     float_count ++;
                     j = 0;
                     if (float_count == 3) break;
                 }
            }

            position_list.push_back((float)atof((const char *)(buffer[0])));
            position_list.push_back((float)atof((const char *)(buffer[1])));
            position_list.push_back((float)atof((const char *)(buffer[2])));
        }
        // texture
        else if (model_data[line_start] == 'v' && model_data[line_start + 1] == 't')
        {
            char buffer[3][64] = {};
            int float_count = 0;
            int j = 0;
            for (int i = line_start + 3; i < line_end; i++)
            {
                if (model_data[i] != ' ' && model_data[i] != '\n')
                {
                    buffer[float_count][j++] = model_data[i];
                } else
                {
                    float_count ++;
                    j = 0;
                    if (float_count == 3) break;
                }
            }

            texture_list.push_back((float)atof((const char *)(buffer[0])));
            texture_list.push_back((float)atof((const char *)(buffer[1])));
        }
        // normal
        else if (model_data[line_start] == 'v' && model_data[line_start + 1] == 'n')
        {
            char buffer[3][64] = {};
            int float_count = 0;
            int j = 0;
            for (int i = line_start + 3; i < line_end; i++)
            {
                if (model_data[i] != ' ' && model_data[i] != '\n')
                {
                    buffer[float_count][j++] = model_data[i];
                } else
                {
                    float_count ++;
                    j = 0;
                    if (float_count == 3) break;
                }
            }

            normal_list.push_back((float)atof((const char *)(buffer[0])));
            normal_list.push_back((float)atof((const char *)(buffer[1])));
            normal_list.push_back((float)atof((const char *)(buffer[2])));
        }
        // face
        else if (model_data[line_start] == 'f' && model_data[line_start + 1] == ' ') {

            if (!has_init_vertex_data)
            {
                int point_number = position_list.size() / 3;
                vertex_data.emplace(VertexAttribType::POSITION_F3, new uint8_t [point_number * 3 * sizeof(float)] );
                vertex_data.emplace(VertexAttribType::NORMAL_F3, new uint8_t [point_number * 3 * sizeof(float)] );
                vertex_data.emplace(VertexAttribType::UV1_F2, new uint8_t [point_number * 2 * sizeof(float)]);

                memcpy(vertex_data[VertexAttribType::POSITION_F3], position_list.data(), point_number * 3 * sizeof(float));

                has_init_vertex_data = true;
            }

            char buffer[3][64] = {};
            int float_count = 0;
            int j = 0;
            for (int i = line_start + 2; i < line_end; i++)
            {
                if (model_data[i] != ' ' && model_data[i] != '\n')
                {
                    buffer[float_count][j++] = model_data[i];
                } else
                {
                    float_count ++;
                    j = 0;
                    if (float_count == 3) break;
                }
            }

            std::vector<int> index_list;
            GetFaceIndex((const char * )model_data + line_start + 2, line_end - line_start - 1, index_list);

            if (index_list.size() == 2)
            {

            }
            else if (index_list.size() == 3)
            {

            }
        }
    }
}

void ObjFileParser::GetFaceIndex(const char * start, int str_len, std::vector<int> & result)
{
    char buffer[3][64] = {};
    int index_count = 0;
    int j = 0;
    for (int i = 0; i < str_len; i++)
    {
        if (start[i] != ' ' && start[i] != '\n' && start[i] != '/')
        {
            buffer[index_count][j++] = start[i];
        }
        else
        {
            index_count ++;
            j = 0;
        }
    }

    for (int i = 0; i < index_count; i++)
    {
        result.push_back(atoi(buffer[i]));
    }
}